﻿extern alias hostWA;
extern alias hostCA;
extern alias hostWX;
extern alias hostCX;

using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Threading;
using MyUtils;

namespace FitAutomation.FitProcess
{
	/// <summary>
	/// Main entry point for FitProcess users
	/// </summary>
	public static class FitProcessFactory
	{
		/// <summary>
		/// Create new separate process for your objects
		/// </summary>
		/// <returns></returns>
		public static FitProcessAccessor CreateProcess()
		{
			return CreateProcess(false, false);
		}

		/// <summary>
		/// Create new separate process for your objects
		/// </summary>
		/// <returns></returns>
		public static FitProcessAccessor CreateProcess(bool showConsole)
		{
			return CreateProcess(showConsole, false);
		}

		/// <summary>
		/// Create new separate process for your objects
		/// </summary>
		/// <returns></returns>
		public static FitProcessAccessor CreateProcess(bool showConsole, bool forceX86)
		{
			var port = 1024 + 1024.Random();

			var mutexId = Guid.NewGuid();
			var mutex = new EventWaitHandle(false, EventResetMode.ManualReset, mutexId.ToString());

			var hash = new StringDictionary();

			var asm1 = Assembly.GetCallingAssembly();

			hash[asm1.Location.ToLowerInvariant()] = null;

			var asm2 = Assembly.GetEntryAssembly();

			if (asm2 != null)
			{
				hash[asm2.Location.ToLowerInvariant()] = null;
			}

			var args = "port=" + port + " mutex=" + mutexId;

			foreach (var asm in hash.Keys)
			{
				args += " \"load=" + asm+"\"";
			}

			var entryPointType = GetEntryPoint(showConsole, forceX86);

			var exe = entryPointType.Assembly.Location;
			var process =Process.Start(exe, args);

			var accessor = new FitProcessAccessor(port, process);

			while (!mutex.WaitOne(5000))
			{
				if (!Debugger.IsAttached)
				{
					throw new Exception("Host process is not started");
				}
			}

			accessor.Connect();
			return accessor;
		}

		static Type GetEntryPoint(bool showConsole, bool forceX86)
		{
			return showConsole
			       	? (forceX86
			       	   	? typeof(hostCX::FitAutomation.FitProcess.ProgramEntryPoint)
			       	   	: typeof(hostCA::FitAutomation.FitProcess.ProgramEntryPoint))
			       	: (forceX86
			       	   	? typeof(hostWX::FitAutomation.FitProcess.ProgramEntryPoint)
			       	   	: typeof(hostWA::FitAutomation.FitProcess.ProgramEntryPoint));
		}

		#region Hide object members
		/// <summary>Do not call this method.</summary>
		[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "b")]
		[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "a")]
		[Obsolete("Do not call this method", true)]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public new static bool Equals(object a, object b)
		{
			throw new InvalidOperationException("Do not call this method");
		}

		/// <summary>Do not call this method.</summary>
		[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "b")]
		[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "a")]
		[Obsolete("Do not call this method", true)]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public new static bool ReferenceEquals(object a, object b)
		{
			throw new InvalidOperationException("Do not call this method");
		}
		#endregion
	}
}
